Load libraries


#### Load packages ####
library(camprotR)
library(tidyverse)
library(MSnbase)
library(biobroom)
library(gtools)

Read in the PSM data

psm_res <- readRDS('../results/psm_res.rds')

Plot the tag intensities, without annotating notch.

psm_res %>% names() %>% lapply(function(x){
  p <- psm_res[[x]] %>%
    log(base=2) %>%
    plot_quant(method='histogram') +
    theme_camprot() +
    xlab('Reporter ion intensity (log2)')
  
  filename <- file.path('../results/plots/', paste0(gsub(':| ', '', x), '_ion_intensities.png'))
  
  ggsave(filename, p, height=5, width=5)
  print(p)
})
[[1]]

[[2]]

[[3]]

Plotting the proportion of missing values


psm_res %>% names() %>% lapply(function(x){
  
  all <- psm_res[[x]]
  hs <- all[fData(all)$species=='H.sapiens']
  sc <- all[fData(all)$species=='S.cerevisiae']
  
  slices <- list('All'=all, 'H.sapiens'=hs, 'S.cerevisiae'=sc)
  for(slice in names(slices)){
    p <- slices[[slice]] %>% plot_missing_SN() +
      ggtitle(sprintf('%s - %s', x, slice))
    print(p)
  
    p <- slices[[slice]] %>% plot_missing_SN_per_sample() +
      ggtitle(sprintf('%s - %s', x, slice))
    print(p)
  }
  return(NULL)
})
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

OK, so essentially all the missing values are restricted to PSMs with low (<20) Signal:Noise ratios.


source('../R/get_quant_vs_mean.R')


quant_vs_mean <- psm_res %>% lapply(get_quant_vs_mean)

quant_vs_mean <- quant_vs_mean %>% lapply(function(x){
  x %>%
    mutate(binned_interference=Hmisc::cut2(
      Isolation.Interference.in.Percent, cuts=c(0,1,5,10,seq(20,100,20))),
      binned_average_sn=Hmisc::cut2(Average.Reporter.SN, cuts=c(0,10,20,30,40,60,100)),
      binned_intensity=Hmisc::cut2(intensity, cuts=c(0,10,20,30,40,60,100)),
      binned_delta=Hmisc::cut2(Delta.Score, cuts=c(seq(0,.6,.1), 1)))
})

quant_vs_mean %>% lapply(dim)
$`AGC: 2E5`
[1] 1980560      24

$`AGC: 5E4`
[1] 2166658      24

$`Tune v3`
[1] 2196642      24
plot(density(quant_vs_mean$`AGC: 5E4`$Delta.Score))

plot(density(quant_vs_mean$`AGC: 5E4`$Isolation.Interference.in.Percent))


quant_vs_mean %>% names() %>% lapply(function(x){
  p <- quant_vs_mean[[x]] %>%
    select(id, species, binned_average_sn, binned_interference, binned_delta) %>%
    unique() %>%
    group_by(species, binned_average_sn, binned_interference, binned_delta) %>%
    tally() %>%
    ggplot(aes(binned_interference, n)) +
    geom_bar(stat='identity') +
    facet_wrap(~species, scales='free') +
    theme_camprot(base_size=15) +
    theme(axis.text.x=element_text(angle=45, vjust=1, hjust=1)) +
    ggtitle(x)
  
  print(p)
  
  print(p + aes(binned_average_sn) +
          xlab('Signal/Noise'))
  
  print(p + aes(binned_delta) +
          xlab('Delta score'))
  
  return(NULL)
})
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

Define the expected ratios from the experimental design

exp_design <- pData(psm_res$`AGC: 2E5`) %>%
  select(condition, S.cerevisiae=yeast, H.sapiens=human) %>%
  unique()
  
sc_spikes <- exp_design$S.cerevisiae
hs_spikes <- exp_design$H.sapiens

get_ground_truth <- function(sc_spikes, hs_spikes, ix_1, ix_2){
  comparison <- sprintf('%s vs %s', sc_spikes[ix_2], sc_spikes[ix_1])
  hs_ground_truth <- hs_spikes[ix_2]/hs_spikes[ix_1]
  sc_ground_truth <- sc_spikes[ix_2]/sc_spikes[ix_1]
  return(c(comparison, hs_ground_truth, sc_ground_truth))
}


expected <- apply(permutations(n=3,r=2), 1, function(x){
  get_ground_truth(sc_spikes, hs_spikes, x[1], x[2])
}) %>% t() %>% data.frame() %>%
  setNames(c('comparison', 'H.sapiens', 'S.cerevisiae')) %>%
  mutate_at(vars(S.cerevisiae, 
                 H.sapiens), 
            funs(as.numeric)) %>%
  pivot_longer(-comparison, names_to='species', values_to='expected')

print(expected)

positive_comparisons <- expected %>% filter(species=='S.cerevisiae', expected>1) %>%
  pull(comparison)

Visualising how interference and tag intensity affect observed fold changes

quant_vs_mean %>% names() %>% lapply(function(x){
  p <- quant_vs_mean[[x]] %>%
    filter(Isolation.Interference.in.Percent<=50, # no need to consider interference>=50%
           comparison %in% positive_comparisons) %>% 
    filter(species=='S.cerevisiae', !below_notch) %>%
    ggplot(aes(diff, colour=binned_intensity)) +
    geom_density() +
    theme_camprot(base_size=15) +
    theme(axis.text.x=element_text(angle=45, vjust=1, hjust=1)) +
    facet_grid(binned_interference~comparison, scales='free') +
    geom_vline(aes(xintercept=log2(expected)),
               data=expected[(expected$species=='S.cerevisiae' &
                                expected$comparison %in% positive_comparisons),],
               colour=get_cat_palette(1), linetype=2) +
    ylab('Density') +
    xlab('Difference in intensity') +
    xlim(-6,3) +
    ggtitle(x) +
    scale_colour_discrete(name='Intensity')
  
  print(p)
  print(p + aes(colour=binned_interference) + facet_grid(binned_average_sn~comparison) +
    scale_colour_discrete(name='Interference (%)'))
  
  print(p + aes(colour=binned_interference) + facet_grid(binned_delta~comparison) +
    scale_colour_discrete(name='Interference (%)'))
  
  
  print(p + aes(colour=binned_delta) + facet_wrap(~comparison) +
          coord_cartesian(xlim=c(-2, 3)) +
    scale_colour_manual(name='Delta score', values=get_cat_palette(7)))

  return(NULL)
})
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

quant_vs_mean$`AGC: 5E4` %>%
    filter(Isolation.Interference.in.Percent<=50, # no need to consider interference>=50%
           comparison %in% positive_comparisons) %>% 
    filter(species=='S.cerevisiae', !below_notch) %>%
    ggplot(aes(Delta.Score, diff)) +
    geom_point(size=0.1, alpha=0.1) +
    geom_smooth() +
    theme_camprot(base_size=15) +
    theme(axis.text.x=element_text(angle=45, vjust=1, hjust=1)) +
    facet_grid(~comparison, scales='free') +
    geom_hline(aes(yintercept=log2(expected)),
               data=expected[(expected$species=='S.cerevisiae' &
                                expected$comparison %in% positive_comparisons),],
               colour=get_cat_palette(1), linetype=2) +
    ylab('Fold change (log2)') +
    xlab('Delta scores')

Summarise the fold changes to compare median fold changes over bins of tag intensity and interference

quant_vs_mean %>% names() %>% lapply(function(x){
    p <- quant_vs_mean[[x]] %>%
    filter(Isolation.Interference.in.Percent<=60) %>% # no need to consider interference>=60%
    filter(species=='S.cerevisiae', !below_notch, comparison=='6 vs 1') %>%
    group_by(binned_interference, binned_intensity) %>%
    summarise(median_diff=2^median(diff, na.rm=TRUE), n=length(diff)) %>%
    ggplot(aes(binned_interference, binned_intensity, fill=median_diff)) +
    geom_tile(colour='grey') +
    theme_camprot(base_size=15) +
    scale_fill_gradient(high=get_cat_palette(2)[2],
                        low='white',
                        limits=c(0, 6), name='Observed\nfold change') +
    theme(axis.text.x=element_text(angle=45, vjust=1, hjust=1)) +
    xlab('Binned interference') +
    ylab('Binned intensity') +
    ggtitle(x)
    
    print(p + geom_text(aes(label=round(median_diff, 1)), size=3))
    
    print(p +
            aes(fill=n) +
            scale_fill_gradient(high=get_cat_palette(3)[3],
                                low='white') +
            geom_text(aes(label=n), size=3) )
})
`summarise()` has grouped output by 'binned_interference'. You can override using the `.groups` argument.
[[1]]

[[2]]

[[3]]

Repeat the above, but also split by Delta

quant_vs_mean %>% names() %>% lapply(function(x){
    p <- quant_vs_mean[[x]] %>%
    filter(Isolation.Interference.in.Percent<=60) %>% # no need to consider interference>=60%
    filter(species=='S.cerevisiae', !below_notch, comparison=='6 vs 1') %>%
    group_by(binned_interference, binned_intensity, binned_delta) %>%
    summarise(median_diff=2^median(diff, na.rm=TRUE), n=length(diff)) %>%
    ggplot(aes(binned_interference, binned_intensity, fill=median_diff)) +
    geom_tile(colour='grey') +
    theme_camprot(base_size=10) +
    scale_fill_gradient(high=get_cat_palette(2)[2],
                        low='white',
                        limits=c(0, 6), name='Observed\nfold change') +
    theme(axis.text.x=element_text(angle=45, vjust=1, hjust=1)) +
    xlab('Binned interference') +
    ylab('Binned intensity') +
    ggtitle(x) +
      facet_wrap(~binned_delta)
    
    print(p + geom_text(aes(label=round(median_diff, 1)), size=3))
    
    print(p +
            aes(fill=n) +
            scale_fill_gradient(high=get_cat_palette(3)[3],
                                low='white') +
            geom_text(aes(label=n), size=3) )
})
`summarise()` has grouped output by 'binned_interference', 'binned_intensity'. You can override using the `.groups` argument.
[[1]]

[[2]]

[[3]]

Let’s check how isolation interference and delta interact with tag intensity to impact the PSM-level fold change estimates. We will just focus on PSMs with interference <= 60%.

quant_vs_mean %>% names() %>% lapply(function(x){
  
  p <- quant_vs_mean[[x]] %>%
     # Don't want to consider interference > 60% 
    filter(species=='S.cerevisiae', Isolation.Interference.in.Percent<=60,
           !comparison %in% positive_comparisons) %>%
    ggplot(aes(log2(intensity), diff)) +
    theme_camprot(base_size=12) +
    facet_wrap(~comparison, scales='free_y') +
    geom_hline(aes(yintercept=log2(expected)),
               data=(expected %>%
                       filter(species=='S.cerevisiae',
                              !comparison %in% positive_comparisons)),
               colour='black', linetype=2) +
    xlab('Tag intensity (log2)') +
    ylab('Difference in intensity (log2)') +
    ggtitle(x)
  
  print(p + geom_point(size=0.1, alpha=0.1))
  print(p + geom_point(size=0.1, alpha=0.1) + geom_smooth(se=FALSE, size=0.5))
  print(p + geom_point(size=0.1, alpha=0.1, colour='grey80') +
          geom_smooth(aes(colour=binned_interference), se=FALSE, size=0.5) +
    scale_colour_manual(values=c(get_cat_palette(6)),
                        name='Isolation interference (%)'))
  print(p + geom_point(size=0.1, alpha=0.1, colour='grey80') +
          geom_smooth(se=FALSE, size=0.5) +
          facet_grid(binned_delta~comparison))
  print(p + geom_point(size=0.1, alpha=0.1, colour='grey80') +
          geom_smooth(aes(colour=binned_delta), se=FALSE, size=0.5) +
    scale_colour_manual(values=c(get_cat_palette(7)),
                        name='Delta score'))

  return(NULL)
})
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

Based on the above, I’m going to use the following range of thresholds: - Delta >= [0, 0.2, 0.5] - Isolation interference <= [10%, 50%, 100%] - Signal/Noise <= [0]

OK, so as we expect, the observed fold changes tend towards the truth as tag intensity increases. At very high tag intensities, there is an issue with more PSMs being false identifications so the observed ratios we observe is the ratio from a human protein, hence the ‘uptick’ in ratios for e.g ‘1 vs 6’ at high intensities. We also observe the clear understatimate of ratios when the tag intensity is below the notch.

We observe that this ‘uptick’ only occurs when Delta score < 0.5. This fits with the expectation that these PSMs are actually from human peptides, but the rank 1 peptide is a yeast peptide, likely an ortholog.

We also observe that in the range of tag intensities where the ratio is close to the truth (~2^3 - 2^7), the observed ratio is closer to the truth with low interference (<20%)

Let’s plot the tag intensity vs difference in intensity for all interference thresholds

interference_thresholds <- c(10, 50, 100)
for(x in names(quant_vs_mean)){
  
    for(int_threshold in interference_thresholds){
      tmp_data <-  quant_vs_mean[[x]] %>%
        filter(species!='mixed',
               !comparison %in% positive_comparisons,
               Isolation.Interference.in.Percent<=int_threshold)
      
      p <- tmp_data %>%
        ggplot(aes(log2(intensity), diff)) +
        geom_point(size=0.05, alpha=0.05, colour='grey10') +
        geom_density2d(size=0.3, colour=get_cat_palette(2)[2]) +
        theme_camprot(base_size=12) +
        facet_grid(species~comparison, scales='free_y') +
        geom_hline(aes(yintercept=log2(expected)),
                   data=expected[!expected$comparison %in% positive_comparisons,],
                   colour='black', linetype=2) +
        xlab('Tag intensity (log2)') +
        ylab('Difference in intensity (log2)') +
        coord_cartesian(ylim=c(-4,4))
    
      print(p + ggtitle(sprintf('%s - Interference <= %s', x, int_threshold)))
  }   
}

Now, let’s filter the PSMs against the interference and average S/N thresholds +/- notch filtering.


delta_thresholds <- c(0, 0.2, 0.5)
interference_thresholds <- c(10, 50, 100)
sn_thresholds <- c(0, 10)
notch_thresholded <- c(TRUE, FALSE)

combinations <- as.list(as.data.frame(t(crossing(
  delta_thresholds,
  interference_thresholds,
  sn_thresholds,
  notch_thresholded))))

names(combinations) <- lapply(combinations, FUN=function(x){
  sprintf('%s, %s, %s, %s', x[1], x[2], x[3], x[4])
})

psm_res_flt <- psm_res %>% lapply(function(x){
  
  x <- x %>% log(base=2) %>% MSnbase::normalise(method='diff.median')
  exprs(x) <- 2^exprs(x)
    
  combinations %>% lapply(function(thresholds){

    delta_threshold <- thresholds[1]
    interference_threshold <- thresholds[2]
    sn_threshold<- thresholds[3]
    notch <- thresholds[4]
    
    message(sprintf(paste0('Thresholding with delta >= %s, co-isolation <= %s, ',
                   'average S/N >= %s, notch PSMs removed: %s'),
            delta_threshold, interference_threshold,
            sn_threshold, as.character(as.logical(notch))))
    
    out <- filter_TMT_PSMs(x, inter_thresh=interference_threshold,
                           sn_thresh=sn_threshold, verbose=FALSE)
    
    out <- out[fData(out)$Delta.Score>=delta_threshold,]
    
    if(notch){
      out <- out[apply(exprs(out), 1, function(x) min(x, na.rm=TRUE))>log2(5.75)]
    }
  
    out
  })
})
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.2, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 10, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 50, average S/N >= 10, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 0, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 0, notch PSMs removed: TRUE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 10, notch PSMs removed: FALSE
Thresholding with delta >= 0.5, co-isolation <= 100, average S/N >= 10, notch PSMs removed: TRUE
dim(psm_res_flt$`AGC: 5E4`$`0.5, 10, 0, 0`)
[1] 19975    10
for(x in names(quant_vs_mean)){
  
    tmp_data <-  quant_vs_mean[[x]] %>%
      filter(species!='mixed',
             !comparison %in% positive_comparisons,
             Isolation.Interference.in.Percent<=10,
             Delta.Score>=0.5)
    
    tmp_data_for_smooth <- tmp_data %>%
      filter(species=='H.sapiens' | ((species=='S.cerevisiae' & intensity < 2^6.5)))

    p <- tmp_data %>%
      ggplot(aes(log2(intensity), diff)) +
      geom_point(size=0.05, alpha=0.05, colour='grey10') +
      geom_smooth(data=tmp_data_for_smooth, aes(log2(intensity), diff)) +
      theme_camprot(base_size=12) +
      facet_grid(species~comparison, scales='free_y') +
      geom_hline(aes(yintercept=log2(expected)),
                 data=expected[!expected$comparison %in% positive_comparisons,],
                 colour='grey', linetype=2) +
      xlab('Reporter ion intensity (log2)') +
      ylab('Difference in intensity (log2)') +
      coord_cartesian(ylim=c(-5,3))
    
    ggsave(sprintf('../results/plots/%s_psm_fold_changes.png', gsub('[: ]', '', x)), p)
    
    print(p + ggtitle(x))

}
Saving 7 x 7 in image

# define datasets to plot intensities, notch per protein and missing values 

datasets <- list(c('0, 100, 0, 0'), c('0.5, 10, 0, 0')) 

psm_res_flt %>% names() %>% lapply(function(agc){
  datasets %>% lapply(function(thresholds){
    print(thresholds)
    all <- psm_res_flt[[agc]][[thresholds]]

    hs <- all[fData(all)$species=='H.sapiens']
    sc <- all[fData(all)$species=='S.cerevisiae']
    
    slices <- list('All'=all, 'H.sapiens'=hs, 'S.cerevisiae'=sc)
    for(slice in names(slices)){
      p <- slices[[slice]] %>% plot_TMT_notch() +
        xlab('Reporter ion intensity (log2)') +
        ggtitle(sprintf('%s\n%s\n%s', agc, thresholds, slice))
      print(p)
      
      p2 <- slices[[slice]] %>% plot_TMT_notch(facet_by_sample=TRUE) +
        xlab('Reporter ion intensity (log2)') +
        ggtitle(sprintf('%s\n%s\n%s', agc, thresholds, slice))
      print(p2)

    }
    
    return(NULL)
    
    })
  
  
  return(NULL)
})
[1] "0, 100, 0, 0"
[1] "0.5, 10, 0, 0"
[1] "0, 100, 0, 0"
[1] "0.5, 10, 0, 0"
[1] "0, 100, 0, 0"
[1] "0.5, 10, 0, 0"
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

thresholds <- c('0, 100, 0, 0') 

print(thresholds)
[1] "0, 100, 0, 0"
all <- psm_res_flt[['AGC: 5E4']][[thresholds]]

hs <- all[fData(all)$species=='H.sapiens']
sc <- all[fData(all)$species=='S.cerevisiae']

slices <- list('All'=all, 'H.sapiens'=hs, 'S.cerevisiae'=sc)
for(slice in names(slices)){
  p <- slices[[slice]] %>% plot_TMT_notch() +
    xlab('Reporter ion intensity (log2)') +
    ggtitle(sprintf('%s\n%s', thresholds, slice))
  print(p)
  
  p2 <- slices[[slice]] %>% plot_TMT_notch(facet_by_sample=TRUE) +
    xlab('Reporter ion intensity (log2)') +
    ggtitle(sprintf('%s\n%s', thresholds, slice))
  print(p2)

  ggsave(sprintf('../results/plots/%s_ion_intensities.png', slice), p)
  ggsave(sprintf('../results/plots/%s_ion_intensities_per_tag.png', slice), p2)

}

NA

Tallies for fraction sub-notch PSMs per protein

datasets <- list(c('0.5, 10, 0, 0'))

psm_res_flt %>% names() %>% lapply(function(agc){
  datasets %>% lapply(function(thresholds){

    all <- psm_res_flt[[agc]][[thresholds]]
    hs <- all[fData(all)$species=='H.sapiens']
    sc <- all[fData(all)$species=='S.cerevisiae']
    
    slices <- list('All'=all, 'H.sapiens'=hs, 'S.cerevisiae'=sc)
    for(slice in names(slices)){
      
      notch_per_protein <- get_notch_per_protein(slices[[slice]]) %>%
         mutate(sample=factor(remove_x(sample), colnames(slices[[slice]])))
      
      print(notch_per_protein %>%
        group_by(sample, fraction_below>=0.25) %>%
        tally())
      
      p <- notch_per_protein %>%
        filter(fraction_below>0) %>% 
        ggplot(aes(.data$fraction_below)) +
        geom_histogram(bins = 10) + 
        theme_camprot(base_size = 10) +
        facet_wrap(~sample) + 
        xlab("Fraction at/below notch PSMs") +
        ylab("Proteins") +
        scale_x_continuous(breaks=seq(0,1,0.5))
        
      
      print(p + ggtitle(sprintf('%s\n%s\n%s', agc, thresholds, slice)))
      
      if(agc=='AGC: 5E4' & slice=='All'){
        ggsave('../results/plots/fraction_sub_notch.png', p)
      }
    }
    
    return(NULL)
  })
  
  return(NULL)
  
})
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

Missing values frequencies.

psm_res_flt %>% names() %>% lapply(function(agc){
  datasets %>% lapply(function(thresholds){

    all <- psm_res_flt[[agc]][[thresholds]]
    hs <- all[fData(all)$species=='H.sapiens']
    sc <- all[fData(all)$species=='S.cerevisiae']
    
    slices <- list('All'=all, 'H.sapiens'=hs, 'S.cerevisiae'=sc)
    for(slice in names(slices)) plotNA(slices[[slice]], pNA = 0)

    return(NULL)
  })
  
  return(NULL)
  
})
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

Save out objects for downstream notebooks

saveRDS(quant_vs_mean, '../results/quant_vs_mean.rds')
saveRDS(psm_res_flt, '../results/psm_res_flt.rds')
saveRDS(expected, '../results/expected.rds')
LS0tCnRpdGxlOiAnRmlsdGVyIFBTTXMnCmF1dGhvcjoKICAtIG5hbWU6ICJUb20gU21pdGgiCiAgICBhZmZpbGlhdGlvbjogIkNhbWJyaWRnZSBDZW50cmUgZm9yIFByb3Rlb21pY3MiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKYWJzdHJhY3Q6IHwgCiAgSGVyZSwgd2UgZmlsdGVyIHRoZSBQU00tbGV2ZWwgUEQgb3V0cHV0LCB3aXRoIHRocmVzaG9sZHMgaW5mb3JtZWQgYnkgbWlzc2luZyB2YWx1ZXMsCiAgbm90Y2ggcHJvbWluZW5jZSBhbmQgb2JzZXJ2ZWQgZm9sZCBjaGFuZ2VzIHZzIGdyb3VuZCB0cnV0aHMuCm91dHB1dDoKICBwZGZfZG9jdW1lbnQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdApnZW9tZXRyeTogbWFyZ2luPTFpbgpmb250ZmFtaWx5OiBtYXRocGF6bwpmb250c2l6ZTogMTFwdAotLS0KCkxvYWQgbGlicmFyaWVzCmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFfQoKIyMjIyBMb2FkIHBhY2thZ2VzICMjIyMKbGlicmFyeShjYW1wcm90UikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoTVNuYmFzZSkKbGlicmFyeShiaW9icm9vbSkKbGlicmFyeShndG9vbHMpCmBgYAoKUmVhZCBpbiB0aGUgUFNNIGRhdGEKYGBge3J9CnBzbV9yZXMgPC0gcmVhZFJEUygnLi4vcmVzdWx0cy9wc21fcmVzLnJkcycpCmBgYAoKUGxvdCB0aGUgdGFnIGludGVuc2l0aWVzLCB3aXRob3V0IGFubm90YXRpbmcgbm90Y2guCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpwc21fcmVzICU+JSBuYW1lcygpICU+JSBsYXBwbHkoZnVuY3Rpb24oeCl7CiAgcCA8LSBwc21fcmVzW1t4XV0gJT4lCiAgICBsb2coYmFzZT0yKSAlPiUKICAgIHBsb3RfcXVhbnQobWV0aG9kPSdoaXN0b2dyYW0nKSArCiAgICB0aGVtZV9jYW1wcm90KCkgKwogICAgeGxhYignUmVwb3J0ZXIgaW9uIGludGVuc2l0eSAobG9nMiknKQogIAogIGZpbGVuYW1lIDwtIGZpbGUucGF0aCgnLi4vcmVzdWx0cy9wbG90cy8nLCBwYXN0ZTAoZ3N1YignOnwgJywgJycsIHgpLCAnX2lvbl9pbnRlbnNpdGllcy5wbmcnKSkKICAKICBnZ3NhdmUoZmlsZW5hbWUsIHAsIGhlaWdodD01LCB3aWR0aD01KQp9KQpgYGAKClBsb3R0aW5nIHRoZSBwcm9wb3J0aW9uIG9mIG1pc3NpbmcgdmFsdWVzIApgYGB7cn0KCnBzbV9yZXMgJT4lIG5hbWVzKCkgJT4lIGxhcHBseShmdW5jdGlvbih4KXsKICAKICBhbGwgPC0gcHNtX3Jlc1tbeF1dCiAgaHMgPC0gYWxsW2ZEYXRhKGFsbCkkc3BlY2llcz09J0guc2FwaWVucyddCiAgc2MgPC0gYWxsW2ZEYXRhKGFsbCkkc3BlY2llcz09J1MuY2VyZXZpc2lhZSddCiAgCiAgc2xpY2VzIDwtIGxpc3QoJ0FsbCc9YWxsLCAnSC5zYXBpZW5zJz1ocywgJ1MuY2VyZXZpc2lhZSc9c2MpCiAgZm9yKHNsaWNlIGluIG5hbWVzKHNsaWNlcykpewogICAgcCA8LSBzbGljZXNbW3NsaWNlXV0gJT4lIHBsb3RfbWlzc2luZ19TTigpICsKICAgICAgZ2d0aXRsZShzcHJpbnRmKCclcyAtICVzJywgeCwgc2xpY2UpKQogICAgcHJpbnQocCkKICAKICAgIHAgPC0gc2xpY2VzW1tzbGljZV1dICU+JSBwbG90X21pc3NpbmdfU05fcGVyX3NhbXBsZSgpICsKICAgICAgZ2d0aXRsZShzcHJpbnRmKCclcyAtICVzJywgeCwgc2xpY2UpKQogICAgcHJpbnQocCkKICB9CiAgcmV0dXJuKE5VTEwpCn0pCmBgYApPSywgc28gZXNzZW50aWFsbHkgYWxsIHRoZSBtaXNzaW5nIHZhbHVlcyBhcmUgcmVzdHJpY3RlZCB0byBQU01zIHdpdGggbG93ICg8MjApIFNpZ25hbDpOb2lzZSByYXRpb3MuCgoKYGBge3J9Cgpzb3VyY2UoJy4uL1IvZ2V0X3F1YW50X3ZzX21lYW4uUicpCgoKcXVhbnRfdnNfbWVhbiA8LSBwc21fcmVzICU+JSBsYXBwbHkoZ2V0X3F1YW50X3ZzX21lYW4pCgpxdWFudF92c19tZWFuIDwtIHF1YW50X3ZzX21lYW4gJT4lIGxhcHBseShmdW5jdGlvbih4KXsKICB4ICU+JQogICAgbXV0YXRlKGJpbm5lZF9pbnRlcmZlcmVuY2U9SG1pc2M6OmN1dDIoCiAgICAgIElzb2xhdGlvbi5JbnRlcmZlcmVuY2UuaW4uUGVyY2VudCwgY3V0cz1jKDAsMSw1LDEwLHNlcSgyMCwxMDAsMjApKSksCiAgICAgIGJpbm5lZF9hdmVyYWdlX3NuPUhtaXNjOjpjdXQyKEF2ZXJhZ2UuUmVwb3J0ZXIuU04sIGN1dHM9YygwLDEwLDIwLDMwLDQwLDYwLDEwMCkpLAogICAgICBiaW5uZWRfaW50ZW5zaXR5PUhtaXNjOjpjdXQyKGludGVuc2l0eSwgY3V0cz1jKDAsMTAsMjAsMzAsNDAsNjAsMTAwKSksCiAgICAgIGJpbm5lZF9kZWx0YT1IbWlzYzo6Y3V0MihEZWx0YS5TY29yZSwgY3V0cz1jKHNlcSgwLC42LC4xKSwgMSkpKQp9KQoKcXVhbnRfdnNfbWVhbiAlPiUgbGFwcGx5KGRpbSkKYGBgCmBgYHtyfQpwbG90KGRlbnNpdHkocXVhbnRfdnNfbWVhbiRgQUdDOiA1RTRgJERlbHRhLlNjb3JlKSkKcGxvdChkZW5zaXR5KHF1YW50X3ZzX21lYW4kYEFHQzogNUU0YCRJc29sYXRpb24uSW50ZXJmZXJlbmNlLmluLlBlcmNlbnQpKQpgYGAKCmBgYHtyfQoKcXVhbnRfdnNfbWVhbiAlPiUgbmFtZXMoKSAlPiUgbGFwcGx5KGZ1bmN0aW9uKHgpewogIHAgPC0gcXVhbnRfdnNfbWVhbltbeF1dICU+JQogICAgc2VsZWN0KGlkLCBzcGVjaWVzLCBiaW5uZWRfYXZlcmFnZV9zbiwgYmlubmVkX2ludGVyZmVyZW5jZSwgYmlubmVkX2RlbHRhKSAlPiUKICAgIHVuaXF1ZSgpICU+JQogICAgZ3JvdXBfYnkoc3BlY2llcywgYmlubmVkX2F2ZXJhZ2Vfc24sIGJpbm5lZF9pbnRlcmZlcmVuY2UsIGJpbm5lZF9kZWx0YSkgJT4lCiAgICB0YWxseSgpICU+JQogICAgZ2dwbG90KGFlcyhiaW5uZWRfaW50ZXJmZXJlbmNlLCBuKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArCiAgICBmYWNldF93cmFwKH5zcGVjaWVzLCBzY2FsZXM9J2ZyZWUnKSArCiAgICB0aGVtZV9jYW1wcm90KGJhc2Vfc2l6ZT0xNSkgKwogICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCB2anVzdD0xLCBoanVzdD0xKSkgKwogICAgZ2d0aXRsZSh4KQogIAogIHByaW50KHApCiAgCiAgcHJpbnQocCArIGFlcyhiaW5uZWRfYXZlcmFnZV9zbikgKwogICAgICAgICAgeGxhYignU2lnbmFsL05vaXNlJykpCiAgCiAgcHJpbnQocCArIGFlcyhiaW5uZWRfZGVsdGEpICsKICAgICAgICAgIHhsYWIoJ0RlbHRhIHNjb3JlJykpCiAgCiAgcmV0dXJuKE5VTEwpCn0pCmBgYAoKRGVmaW5lIHRoZSBleHBlY3RlZCByYXRpb3MgZnJvbSB0aGUgZXhwZXJpbWVudGFsIGRlc2lnbgpgYGB7cn0KZXhwX2Rlc2lnbiA8LSBwRGF0YShwc21fcmVzJGBBR0M6IDJFNWApICU+JQogIHNlbGVjdChjb25kaXRpb24sIFMuY2VyZXZpc2lhZT15ZWFzdCwgSC5zYXBpZW5zPWh1bWFuKSAlPiUKICB1bmlxdWUoKQogIApzY19zcGlrZXMgPC0gZXhwX2Rlc2lnbiRTLmNlcmV2aXNpYWUKaHNfc3Bpa2VzIDwtIGV4cF9kZXNpZ24kSC5zYXBpZW5zCgpnZXRfZ3JvdW5kX3RydXRoIDwtIGZ1bmN0aW9uKHNjX3NwaWtlcywgaHNfc3Bpa2VzLCBpeF8xLCBpeF8yKXsKICBjb21wYXJpc29uIDwtIHNwcmludGYoJyVzIHZzICVzJywgc2Nfc3Bpa2VzW2l4XzJdLCBzY19zcGlrZXNbaXhfMV0pCiAgaHNfZ3JvdW5kX3RydXRoIDwtIGhzX3NwaWtlc1tpeF8yXS9oc19zcGlrZXNbaXhfMV0KICBzY19ncm91bmRfdHJ1dGggPC0gc2Nfc3Bpa2VzW2l4XzJdL3NjX3NwaWtlc1tpeF8xXQogIHJldHVybihjKGNvbXBhcmlzb24sIGhzX2dyb3VuZF90cnV0aCwgc2NfZ3JvdW5kX3RydXRoKSkKfQoKCmV4cGVjdGVkIDwtIGFwcGx5KHBlcm11dGF0aW9ucyhuPTMscj0yKSwgMSwgZnVuY3Rpb24oeCl7CiAgZ2V0X2dyb3VuZF90cnV0aChzY19zcGlrZXMsIGhzX3NwaWtlcywgeFsxXSwgeFsyXSkKfSkgJT4lIHQoKSAlPiUgZGF0YS5mcmFtZSgpICU+JQogIHNldE5hbWVzKGMoJ2NvbXBhcmlzb24nLCAnSC5zYXBpZW5zJywgJ1MuY2VyZXZpc2lhZScpKSAlPiUKICBtdXRhdGVfYXQodmFycyhTLmNlcmV2aXNpYWUsIAogICAgICAgICAgICAgICAgIEguc2FwaWVucyksIAogICAgICAgICAgICBmdW5zKGFzLm51bWVyaWMpKSAlPiUKICBwaXZvdF9sb25nZXIoLWNvbXBhcmlzb24sIG5hbWVzX3RvPSdzcGVjaWVzJywgdmFsdWVzX3RvPSdleHBlY3RlZCcpCgpwcmludChleHBlY3RlZCkKCnBvc2l0aXZlX2NvbXBhcmlzb25zIDwtIGV4cGVjdGVkICU+JSBmaWx0ZXIoc3BlY2llcz09J1MuY2VyZXZpc2lhZScsIGV4cGVjdGVkPjEpICU+JQogIHB1bGwoY29tcGFyaXNvbikKYGBgCgoKClZpc3VhbGlzaW5nIGhvdyBpbnRlcmZlcmVuY2UgYW5kIHRhZyBpbnRlbnNpdHkgYWZmZWN0IG9ic2VydmVkIGZvbGQgY2hhbmdlcwpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgd2FybmluZz1GQUxTRX0KcXVhbnRfdnNfbWVhbiAlPiUgbmFtZXMoKSAlPiUgbGFwcGx5KGZ1bmN0aW9uKHgpewogIHAgPC0gcXVhbnRfdnNfbWVhbltbeF1dICU+JQogICAgZmlsdGVyKElzb2xhdGlvbi5JbnRlcmZlcmVuY2UuaW4uUGVyY2VudDw9NTAsICMgbm8gbmVlZCB0byBjb25zaWRlciBpbnRlcmZlcmVuY2U+PTUwJQogICAgICAgICAgIGNvbXBhcmlzb24gJWluJSBwb3NpdGl2ZV9jb21wYXJpc29ucykgJT4lIAogICAgZmlsdGVyKHNwZWNpZXM9PSdTLmNlcmV2aXNpYWUnLCAhYmVsb3dfbm90Y2gpICU+JQogICAgZ2dwbG90KGFlcyhkaWZmLCBjb2xvdXI9YmlubmVkX2ludGVuc2l0eSkpICsKICAgIGdlb21fZGVuc2l0eSgpICsKICAgIHRoZW1lX2NhbXByb3QoYmFzZV9zaXplPTE1KSArCiAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIHZqdXN0PTEsIGhqdXN0PTEpKSArCiAgICBmYWNldF9ncmlkKGJpbm5lZF9pbnRlcmZlcmVuY2V+Y29tcGFyaXNvbiwgc2NhbGVzPSdmcmVlJykgKwogICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1sb2cyKGV4cGVjdGVkKSksCiAgICAgICAgICAgICAgIGRhdGE9ZXhwZWN0ZWRbKGV4cGVjdGVkJHNwZWNpZXM9PSdTLmNlcmV2aXNpYWUnICYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBlY3RlZCRjb21wYXJpc29uICVpbiUgcG9zaXRpdmVfY29tcGFyaXNvbnMpLF0sCiAgICAgICAgICAgICAgIGNvbG91cj1nZXRfY2F0X3BhbGV0dGUoMSksIGxpbmV0eXBlPTIpICsKICAgIHlsYWIoJ0RlbnNpdHknKSArCiAgICB4bGFiKCdEaWZmZXJlbmNlIGluIGludGVuc2l0eScpICsKICAgIHhsaW0oLTYsMykgKwogICAgZ2d0aXRsZSh4KSArCiAgICBzY2FsZV9jb2xvdXJfZGlzY3JldGUobmFtZT0nSW50ZW5zaXR5JykKICAKICBwcmludChwKQogIHByaW50KHAgKyBhZXMoY29sb3VyPWJpbm5lZF9pbnRlcmZlcmVuY2UpICsgZmFjZXRfZ3JpZChiaW5uZWRfYXZlcmFnZV9zbn5jb21wYXJpc29uKSArCiAgICBzY2FsZV9jb2xvdXJfZGlzY3JldGUobmFtZT0nSW50ZXJmZXJlbmNlICglKScpKQogIAogIHByaW50KHAgKyBhZXMoY29sb3VyPWJpbm5lZF9pbnRlcmZlcmVuY2UpICsgZmFjZXRfZ3JpZChiaW5uZWRfZGVsdGF+Y29tcGFyaXNvbikgKwogICAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKG5hbWU9J0ludGVyZmVyZW5jZSAoJSknKSkKICAKICAKICBwcmludChwICsgYWVzKGNvbG91cj1iaW5uZWRfZGVsdGEpICsgZmFjZXRfd3JhcCh+Y29tcGFyaXNvbikgKwogICAgICAgICAgY29vcmRfY2FydGVzaWFuKHhsaW09YygtMiwgMykpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwobmFtZT0nRGVsdGEgc2NvcmUnLCB2YWx1ZXM9Z2V0X2NhdF9wYWxldHRlKDcpKSkKCiAgcmV0dXJuKE5VTEwpCn0pCmBgYAoKYGBge3J9CnF1YW50X3ZzX21lYW4kYEFHQzogNUU0YCAlPiUKICAgIGZpbHRlcihJc29sYXRpb24uSW50ZXJmZXJlbmNlLmluLlBlcmNlbnQ8PTUwLCAjIG5vIG5lZWQgdG8gY29uc2lkZXIgaW50ZXJmZXJlbmNlPj01MCUKICAgICAgICAgICBjb21wYXJpc29uICVpbiUgcG9zaXRpdmVfY29tcGFyaXNvbnMpICU+JSAKICAgIGZpbHRlcihzcGVjaWVzPT0nUy5jZXJldmlzaWFlJywgIWJlbG93X25vdGNoKSAlPiUKICAgIGdncGxvdChhZXMoRGVsdGEuU2NvcmUsIGRpZmYpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC4xLCBhbHBoYT0wLjEpICsKICAgIGdlb21fc21vb3RoKCkgKwogICAgdGhlbWVfY2FtcHJvdChiYXNlX3NpemU9MTUpICsKICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgdmp1c3Q9MSwgaGp1c3Q9MSkpICsKICAgIGZhY2V0X2dyaWQofmNvbXBhcmlzb24sIHNjYWxlcz0nZnJlZScpICsKICAgIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9bG9nMihleHBlY3RlZCkpLAogICAgICAgICAgICAgICBkYXRhPWV4cGVjdGVkWyhleHBlY3RlZCRzcGVjaWVzPT0nUy5jZXJldmlzaWFlJyAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwZWN0ZWQkY29tcGFyaXNvbiAlaW4lIHBvc2l0aXZlX2NvbXBhcmlzb25zKSxdLAogICAgICAgICAgICAgICBjb2xvdXI9Z2V0X2NhdF9wYWxldHRlKDEpLCBsaW5ldHlwZT0yKSArCiAgICB5bGFiKCdGb2xkIGNoYW5nZSAobG9nMiknKSArCiAgICB4bGFiKCdEZWx0YSBzY29yZXMnKQpgYGAKClN1bW1hcmlzZSB0aGUgZm9sZCBjaGFuZ2VzIHRvIGNvbXBhcmUgbWVkaWFuIGZvbGQgY2hhbmdlcyBvdmVyIGJpbnMgb2YgdGFnIGludGVuc2l0eSBhbmQgaW50ZXJmZXJlbmNlCmBgYHtyfQpxdWFudF92c19tZWFuICU+JSBuYW1lcygpICU+JSBsYXBwbHkoZnVuY3Rpb24oeCl7CiAgICBwIDwtIHF1YW50X3ZzX21lYW5bW3hdXSAlPiUKICAgIGZpbHRlcihJc29sYXRpb24uSW50ZXJmZXJlbmNlLmluLlBlcmNlbnQ8PTYwKSAlPiUgIyBubyBuZWVkIHRvIGNvbnNpZGVyIGludGVyZmVyZW5jZT49NjAlCiAgICBmaWx0ZXIoc3BlY2llcz09J1MuY2VyZXZpc2lhZScsICFiZWxvd19ub3RjaCwgY29tcGFyaXNvbj09JzYgdnMgMScpICU+JQogICAgZ3JvdXBfYnkoYmlubmVkX2ludGVyZmVyZW5jZSwgYmlubmVkX2ludGVuc2l0eSkgJT4lCiAgICBzdW1tYXJpc2UobWVkaWFuX2RpZmY9Ml5tZWRpYW4oZGlmZiwgbmEucm09VFJVRSksIG49bGVuZ3RoKGRpZmYpKSAlPiUKICAgIGdncGxvdChhZXMoYmlubmVkX2ludGVyZmVyZW5jZSwgYmlubmVkX2ludGVuc2l0eSwgZmlsbD1tZWRpYW5fZGlmZikpICsKICAgIGdlb21fdGlsZShjb2xvdXI9J2dyZXknKSArCiAgICB0aGVtZV9jYW1wcm90KGJhc2Vfc2l6ZT0xNSkgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPWdldF9jYXRfcGFsZXR0ZSgyKVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgbG93PSd3aGl0ZScsCiAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cz1jKDAsIDYpLCBuYW1lPSdPYnNlcnZlZFxuZm9sZCBjaGFuZ2UnKSArCiAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIHZqdXN0PTEsIGhqdXN0PTEpKSArCiAgICB4bGFiKCdCaW5uZWQgaW50ZXJmZXJlbmNlJykgKwogICAgeWxhYignQmlubmVkIGludGVuc2l0eScpICsKICAgIGdndGl0bGUoeCkKICAgIAogICAgcHJpbnQocCArIGdlb21fdGV4dChhZXMobGFiZWw9cm91bmQobWVkaWFuX2RpZmYsIDEpKSwgc2l6ZT0zKSkKICAgIAogICAgcHJpbnQocCArCiAgICAgICAgICAgIGFlcyhmaWxsPW4pICsKICAgICAgICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPWdldF9jYXRfcGFsZXR0ZSgzKVszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3c9J3doaXRlJykgKwogICAgICAgICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPW4pLCBzaXplPTMpICkKfSkKYGBgClJlcGVhdCB0aGUgYWJvdmUsIGJ1dCBhbHNvIHNwbGl0IGJ5IERlbHRhCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9CnF1YW50X3ZzX21lYW4gJT4lIG5hbWVzKCkgJT4lIGxhcHBseShmdW5jdGlvbih4KXsKICAgIHAgPC0gcXVhbnRfdnNfbWVhbltbeF1dICU+JQogICAgZmlsdGVyKElzb2xhdGlvbi5JbnRlcmZlcmVuY2UuaW4uUGVyY2VudDw9NjApICU+JSAjIG5vIG5lZWQgdG8gY29uc2lkZXIgaW50ZXJmZXJlbmNlPj02MCUKICAgIGZpbHRlcihzcGVjaWVzPT0nUy5jZXJldmlzaWFlJywgIWJlbG93X25vdGNoLCBjb21wYXJpc29uPT0nNiB2cyAxJykgJT4lCiAgICBncm91cF9ieShiaW5uZWRfaW50ZXJmZXJlbmNlLCBiaW5uZWRfaW50ZW5zaXR5LCBiaW5uZWRfZGVsdGEpICU+JQogICAgc3VtbWFyaXNlKG1lZGlhbl9kaWZmPTJebWVkaWFuKGRpZmYsIG5hLnJtPVRSVUUpLCBuPWxlbmd0aChkaWZmKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKGJpbm5lZF9pbnRlcmZlcmVuY2UsIGJpbm5lZF9pbnRlbnNpdHksIGZpbGw9bWVkaWFuX2RpZmYpKSArCiAgICBnZW9tX3RpbGUoY29sb3VyPSdncmV5JykgKwogICAgdGhlbWVfY2FtcHJvdChiYXNlX3NpemU9MTApICsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD1nZXRfY2F0X3BhbGV0dGUoMilbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgIGxvdz0nd2hpdGUnLAogICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHM9YygwLCA2KSwgbmFtZT0nT2JzZXJ2ZWRcbmZvbGQgY2hhbmdlJykgKwogICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCB2anVzdD0xLCBoanVzdD0xKSkgKwogICAgeGxhYignQmlubmVkIGludGVyZmVyZW5jZScpICsKICAgIHlsYWIoJ0Jpbm5lZCBpbnRlbnNpdHknKSArCiAgICBnZ3RpdGxlKHgpICsKICAgICAgZmFjZXRfd3JhcCh+YmlubmVkX2RlbHRhKQogICAgCiAgICBwcmludChwICsgZ2VvbV90ZXh0KGFlcyhsYWJlbD1yb3VuZChtZWRpYW5fZGlmZiwgMSkpLCBzaXplPTMpKQogICAgCiAgICBwcmludChwICsKICAgICAgICAgICAgYWVzKGZpbGw9bikgKwogICAgICAgICAgICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9Z2V0X2NhdF9wYWxldHRlKDMpWzNdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvdz0nd2hpdGUnKSArCiAgICAgICAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9biksIHNpemU9MykgKQp9KQpgYGAKCgoKCkxldCdzIGNoZWNrIGhvdyBpc29sYXRpb24gaW50ZXJmZXJlbmNlIGFuZCBkZWx0YSBpbnRlcmFjdCB3aXRoIHRhZyBpbnRlbnNpdHkgdG8gaW1wYWN0IHRoZSBQU00tbGV2ZWwgZm9sZCBjaGFuZ2UgZXN0aW1hdGVzLiBXZSB3aWxsIGp1c3QgZm9jdXMgb24gUFNNcyB3aXRoIGludGVyZmVyZW5jZSA8PSA2MCUuCmBgYHtyLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD03fQpxdWFudF92c19tZWFuICU+JSBuYW1lcygpICU+JSBsYXBwbHkoZnVuY3Rpb24oeCl7CiAgCiAgcCA8LSBxdWFudF92c19tZWFuW1t4XV0gJT4lCiAgICAgIyBEb24ndCB3YW50IHRvIGNvbnNpZGVyIGludGVyZmVyZW5jZSA+IDYwJSAKICAgIGZpbHRlcihzcGVjaWVzPT0nUy5jZXJldmlzaWFlJywgSXNvbGF0aW9uLkludGVyZmVyZW5jZS5pbi5QZXJjZW50PD02MCwKICAgICAgICAgICAhY29tcGFyaXNvbiAlaW4lIHBvc2l0aXZlX2NvbXBhcmlzb25zKSAlPiUKICAgIGdncGxvdChhZXMobG9nMihpbnRlbnNpdHkpLCBkaWZmKSkgKwogICAgdGhlbWVfY2FtcHJvdChiYXNlX3NpemU9MTIpICsKICAgIGZhY2V0X3dyYXAofmNvbXBhcmlzb24sIHNjYWxlcz0nZnJlZV95JykgKwogICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD1sb2cyKGV4cGVjdGVkKSksCiAgICAgICAgICAgICAgIGRhdGE9KGV4cGVjdGVkICU+JQogICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihzcGVjaWVzPT0nUy5jZXJldmlzaWFlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIWNvbXBhcmlzb24gJWluJSBwb3NpdGl2ZV9jb21wYXJpc29ucykpLAogICAgICAgICAgICAgICBjb2xvdXI9J2JsYWNrJywgbGluZXR5cGU9MikgKwogICAgeGxhYignVGFnIGludGVuc2l0eSAobG9nMiknKSArCiAgICB5bGFiKCdEaWZmZXJlbmNlIGluIGludGVuc2l0eSAobG9nMiknKSArCiAgICBnZ3RpdGxlKHgpCiAgCiAgcHJpbnQocCArIGdlb21fcG9pbnQoc2l6ZT0wLjEsIGFscGhhPTAuMSkpCiAgcHJpbnQocCArIGdlb21fcG9pbnQoc2l6ZT0wLjEsIGFscGhhPTAuMSkgKyBnZW9tX3Ntb290aChzZT1GQUxTRSwgc2l6ZT0wLjUpKQogIHByaW50KHAgKyBnZW9tX3BvaW50KHNpemU9MC4xLCBhbHBoYT0wLjEsIGNvbG91cj0nZ3JleTgwJykgKwogICAgICAgICAgZ2VvbV9zbW9vdGgoYWVzKGNvbG91cj1iaW5uZWRfaW50ZXJmZXJlbmNlKSwgc2U9RkFMU0UsIHNpemU9MC41KSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKGdldF9jYXRfcGFsZXR0ZSg2KSksCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU9J0lzb2xhdGlvbiBpbnRlcmZlcmVuY2UgKCUpJykpCiAgcHJpbnQocCArIGdlb21fcG9pbnQoc2l6ZT0wLjEsIGFscGhhPTAuMSwgY29sb3VyPSdncmV5ODAnKSArCiAgICAgICAgICBnZW9tX3Ntb290aChzZT1GQUxTRSwgc2l6ZT0wLjUpICsKICAgICAgICAgIGZhY2V0X2dyaWQoYmlubmVkX2RlbHRhfmNvbXBhcmlzb24pKQogIHByaW50KHAgKyBnZW9tX3BvaW50KHNpemU9MC4xLCBhbHBoYT0wLjEsIGNvbG91cj0nZ3JleTgwJykgKwogICAgICAgICAgZ2VvbV9zbW9vdGgoYWVzKGNvbG91cj1iaW5uZWRfZGVsdGEpLCBzZT1GQUxTRSwgc2l6ZT0wLjUpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWMoZ2V0X2NhdF9wYWxldHRlKDcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0nRGVsdGEgc2NvcmUnKSkKCiAgcmV0dXJuKE5VTEwpCn0pCmBgYApCYXNlZCBvbiB0aGUgYWJvdmUsIEknbSBnb2luZyB0byB1c2UgdGhlIGZvbGxvd2luZyByYW5nZSBvZiB0aHJlc2hvbGRzOgotIERlbHRhID49IFswLCAwLjIsIDAuNV0KLSBJc29sYXRpb24gaW50ZXJmZXJlbmNlIDw9IFsxMCUsIDUwJSwgMTAwJV0KLSBTaWduYWwvTm9pc2UgPD0gWzBdCgpPSywgc28gYXMgd2UgZXhwZWN0LCB0aGUgb2JzZXJ2ZWQgZm9sZCBjaGFuZ2VzIHRlbmQgdG93YXJkcyB0aGUgdHJ1dGggYXMgdGFnIGludGVuc2l0eSBpbmNyZWFzZXMuIEF0IHZlcnkgaGlnaCB0YWcgaW50ZW5zaXRpZXMsIHRoZXJlIGlzIGFuIGlzc3VlIHdpdGggbW9yZSBQU01zIGJlaW5nIGZhbHNlIGlkZW50aWZpY2F0aW9ucyBzbyB0aGUgb2JzZXJ2ZWQgcmF0aW9zIHdlIG9ic2VydmUgaXMgdGhlIHJhdGlvIGZyb20gYSBodW1hbiBwcm90ZWluLCBoZW5jZSB0aGUgJ3VwdGljaycgaW4gcmF0aW9zIGZvciBlLmcgJzEgdnMgNicgYXQgaGlnaCBpbnRlbnNpdGllcy4gV2UgYWxzbyBvYnNlcnZlIHRoZSBjbGVhciB1bmRlcnN0YXRpbWF0ZSBvZiByYXRpb3Mgd2hlbiB0aGUgdGFnIGludGVuc2l0eSBpcyBiZWxvdyB0aGUgbm90Y2guIAoKV2Ugb2JzZXJ2ZSB0aGF0IHRoaXMgJ3VwdGljaycgb25seSBvY2N1cnMgd2hlbiBEZWx0YSBzY29yZSA8IDAuNS4gVGhpcyBmaXRzIHdpdGggdGhlIGV4cGVjdGF0aW9uIHRoYXQgdGhlc2UgUFNNcyBhcmUgYWN0dWFsbHkgZnJvbSBodW1hbiBwZXB0aWRlcywgYnV0IHRoZSByYW5rIDEgcGVwdGlkZSBpcyBhIHllYXN0IHBlcHRpZGUsIGxpa2VseSBhbiBvcnRob2xvZy4gCgpXZSBhbHNvIG9ic2VydmUgdGhhdCBpbiB0aGUgcmFuZ2Ugb2YgdGFnIGludGVuc2l0aWVzIHdoZXJlIHRoZSByYXRpbyBpcyBjbG9zZSB0byB0aGUgdHJ1dGggKH4yXjMgLSAyXjcpLCB0aGUgb2JzZXJ2ZWQgcmF0aW8gaXMgY2xvc2VyIHRvIHRoZSB0cnV0aCB3aXRoIGxvdyBpbnRlcmZlcmVuY2UgKDwyMCUpCgpMZXQncyBwbG90IHRoZSB0YWcgaW50ZW5zaXR5IHZzIGRpZmZlcmVuY2UgaW4gaW50ZW5zaXR5IGZvciBhbGwgaW50ZXJmZXJlbmNlIHRocmVzaG9sZHMKCgpgYGB7ciwgZXZhbD1GQUxTRX0KCmludGVyZmVyZW5jZV90aHJlc2hvbGRzIDwtIGMoMTAsIDUwLCAxMDApCmZvcih4IGluIG5hbWVzKHF1YW50X3ZzX21lYW4pKXsKICAKICAgIGZvcihpbnRfdGhyZXNob2xkIGluIGludGVyZmVyZW5jZV90aHJlc2hvbGRzKXsKICAgICAgdG1wX2RhdGEgPC0gIHF1YW50X3ZzX21lYW5bW3hdXSAlPiUKICAgICAgICBmaWx0ZXIoc3BlY2llcyE9J21peGVkJywKICAgICAgICAgICAgICAgIWNvbXBhcmlzb24gJWluJSBwb3NpdGl2ZV9jb21wYXJpc29ucywKICAgICAgICAgICAgICAgSXNvbGF0aW9uLkludGVyZmVyZW5jZS5pbi5QZXJjZW50PD1pbnRfdGhyZXNob2xkKQogICAgICAKICAgICAgcCA8LSB0bXBfZGF0YSAlPiUKICAgICAgICBnZ3Bsb3QoYWVzKGxvZzIoaW50ZW5zaXR5KSwgZGlmZikpICsKICAgICAgICBnZW9tX3BvaW50KHNpemU9MC4wNSwgYWxwaGE9MC4wNSwgY29sb3VyPSdncmV5MTAnKSArCiAgICAgICAgZ2VvbV9kZW5zaXR5MmQoc2l6ZT0wLjMsIGNvbG91cj1nZXRfY2F0X3BhbGV0dGUoMilbMl0pICsKICAgICAgICB0aGVtZV9jYW1wcm90KGJhc2Vfc2l6ZT0xMikgKwogICAgICAgIGZhY2V0X2dyaWQoc3BlY2llc35jb21wYXJpc29uLCBzY2FsZXM9J2ZyZWVfeScpICsKICAgICAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PWxvZzIoZXhwZWN0ZWQpKSwKICAgICAgICAgICAgICAgICAgIGRhdGE9ZXhwZWN0ZWRbIWV4cGVjdGVkJGNvbXBhcmlzb24gJWluJSBwb3NpdGl2ZV9jb21wYXJpc29ucyxdLAogICAgICAgICAgICAgICAgICAgY29sb3VyPSdibGFjaycsIGxpbmV0eXBlPTIpICsKICAgICAgICB4bGFiKCdUYWcgaW50ZW5zaXR5IChsb2cyKScpICsKICAgICAgICB5bGFiKCdEaWZmZXJlbmNlIGluIGludGVuc2l0eSAobG9nMiknKSArCiAgICAgICAgY29vcmRfY2FydGVzaWFuKHlsaW09YygtNCw0KSkKICAgIAogICAgICBwcmludChwICsgZ2d0aXRsZShzcHJpbnRmKCclcyAtIEludGVyZmVyZW5jZSA8PSAlcycsIHgsIGludF90aHJlc2hvbGQpKSkKICB9ICAgCn0KYGBgCgoKTm93LCBsZXQncyBmaWx0ZXIgdGhlIFBTTXMgYWdhaW5zdCB0aGUgaW50ZXJmZXJlbmNlIGFuZCBhdmVyYWdlIFMvTiB0aHJlc2hvbGRzICsvLSBub3RjaCBmaWx0ZXJpbmcuCgpgYGB7cn0KCmRlbHRhX3RocmVzaG9sZHMgPC0gYygwLCAwLjIsIDAuNSkKaW50ZXJmZXJlbmNlX3RocmVzaG9sZHMgPC0gYygxMCwgNTAsIDEwMCkKc25fdGhyZXNob2xkcyA8LSBjKDAsIDEwKQpub3RjaF90aHJlc2hvbGRlZCA8LSBjKFRSVUUsIEZBTFNFKQoKY29tYmluYXRpb25zIDwtIGFzLmxpc3QoYXMuZGF0YS5mcmFtZSh0KGNyb3NzaW5nKAogIGRlbHRhX3RocmVzaG9sZHMsCiAgaW50ZXJmZXJlbmNlX3RocmVzaG9sZHMsCiAgc25fdGhyZXNob2xkcywKICBub3RjaF90aHJlc2hvbGRlZCkpKSkKCm5hbWVzKGNvbWJpbmF0aW9ucykgPC0gbGFwcGx5KGNvbWJpbmF0aW9ucywgRlVOPWZ1bmN0aW9uKHgpewogIHNwcmludGYoJyVzLCAlcywgJXMsICVzJywgeFsxXSwgeFsyXSwgeFszXSwgeFs0XSkKfSkKCnBzbV9yZXNfZmx0IDwtIHBzbV9yZXMgJT4lIGxhcHBseShmdW5jdGlvbih4KXsKICAKICB4IDwtIHggJT4lIGxvZyhiYXNlPTIpICU+JSBNU25iYXNlOjpub3JtYWxpc2UobWV0aG9kPSdkaWZmLm1lZGlhbicpCiAgZXhwcnMoeCkgPC0gMl5leHBycyh4KQogICAgCiAgY29tYmluYXRpb25zICU+JSBsYXBwbHkoZnVuY3Rpb24odGhyZXNob2xkcyl7CgogICAgZGVsdGFfdGhyZXNob2xkIDwtIHRocmVzaG9sZHNbMV0KICAgIGludGVyZmVyZW5jZV90aHJlc2hvbGQgPC0gdGhyZXNob2xkc1syXQogICAgc25fdGhyZXNob2xkPC0gdGhyZXNob2xkc1szXQogICAgbm90Y2ggPC0gdGhyZXNob2xkc1s0XQogICAgCiAgICBtZXNzYWdlKHNwcmludGYocGFzdGUwKCdUaHJlc2hvbGRpbmcgd2l0aCBkZWx0YSA+PSAlcywgY28taXNvbGF0aW9uIDw9ICVzLCAnLAogICAgICAgICAgICAgICAgICAgJ2F2ZXJhZ2UgUy9OID49ICVzLCBub3RjaCBQU01zIHJlbW92ZWQ6ICVzJyksCiAgICAgICAgICAgIGRlbHRhX3RocmVzaG9sZCwgaW50ZXJmZXJlbmNlX3RocmVzaG9sZCwKICAgICAgICAgICAgc25fdGhyZXNob2xkLCBhcy5jaGFyYWN0ZXIoYXMubG9naWNhbChub3RjaCkpKSkKICAgIAogICAgb3V0IDwtIGZpbHRlcl9UTVRfUFNNcyh4LCBpbnRlcl90aHJlc2g9aW50ZXJmZXJlbmNlX3RocmVzaG9sZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc25fdGhyZXNoPXNuX3RocmVzaG9sZCwgdmVyYm9zZT1GQUxTRSkKICAgIAogICAgb3V0IDwtIG91dFtmRGF0YShvdXQpJERlbHRhLlNjb3JlPj1kZWx0YV90aHJlc2hvbGQsXQogICAgCiAgICBpZihub3RjaCl7CiAgICAgIG91dCA8LSBvdXRbYXBwbHkoZXhwcnMob3V0KSwgMSwgZnVuY3Rpb24oeCkgbWluKHgsIG5hLnJtPVRSVUUpKT5sb2cyKDUuNzUpXQogICAgfQogIAogICAgb3V0CiAgfSkKfSkKCgpgYGAKCgpgYGB7cn0KZGltKHBzbV9yZXNfZmx0JGBBR0M6IDVFNGAkYDAuNSwgMTAsIDAsIDBgKQoKZm9yKHggaW4gbmFtZXMocXVhbnRfdnNfbWVhbikpewogIAogICAgdG1wX2RhdGEgPC0gIHF1YW50X3ZzX21lYW5bW3hdXSAlPiUKICAgICAgZmlsdGVyKHNwZWNpZXMhPSdtaXhlZCcsCiAgICAgICAgICAgICAhY29tcGFyaXNvbiAlaW4lIHBvc2l0aXZlX2NvbXBhcmlzb25zLAogICAgICAgICAgICAgSXNvbGF0aW9uLkludGVyZmVyZW5jZS5pbi5QZXJjZW50PD0xMCwKICAgICAgICAgICAgIERlbHRhLlNjb3JlPj0wLjUpCiAgICAKICAgIHRtcF9kYXRhX2Zvcl9zbW9vdGggPC0gdG1wX2RhdGEgJT4lCiAgICAgIGZpbHRlcihzcGVjaWVzPT0nSC5zYXBpZW5zJyB8ICgoc3BlY2llcz09J1MuY2VyZXZpc2lhZScgJiBpbnRlbnNpdHkgPCAyXjYuNSkpKQoKICAgIHAgPC0gdG1wX2RhdGEgJT4lCiAgICAgIGdncGxvdChhZXMobG9nMihpbnRlbnNpdHkpLCBkaWZmKSkgKwogICAgICBnZW9tX3BvaW50KHNpemU9MC4wNSwgYWxwaGE9MC4wNSwgY29sb3VyPSdncmV5MTAnKSArCiAgICAgIGdlb21fc21vb3RoKGRhdGE9dG1wX2RhdGFfZm9yX3Ntb290aCwgYWVzKGxvZzIoaW50ZW5zaXR5KSwgZGlmZikpICsKICAgICAgdGhlbWVfY2FtcHJvdChiYXNlX3NpemU9MTIpICsKICAgICAgZmFjZXRfZ3JpZChzcGVjaWVzfmNvbXBhcmlzb24sIHNjYWxlcz0nZnJlZV95JykgKwogICAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PWxvZzIoZXhwZWN0ZWQpKSwKICAgICAgICAgICAgICAgICBkYXRhPWV4cGVjdGVkWyFleHBlY3RlZCRjb21wYXJpc29uICVpbiUgcG9zaXRpdmVfY29tcGFyaXNvbnMsXSwKICAgICAgICAgICAgICAgICBjb2xvdXI9J2dyZXknLCBsaW5ldHlwZT0yKSArCiAgICAgIHhsYWIoJ1JlcG9ydGVyIGlvbiBpbnRlbnNpdHkgKGxvZzIpJykgKwogICAgICB5bGFiKCdEaWZmZXJlbmNlIGluIGludGVuc2l0eSAobG9nMiknKSArCiAgICAgIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLTUsMykpCiAgICAKICAgIGdnc2F2ZShzcHJpbnRmKCcuLi9yZXN1bHRzL3Bsb3RzLyVzX3BzbV9mb2xkX2NoYW5nZXMucG5nJywgZ3N1YignWzogXScsICcnLCB4KSksIHApCiAgICAKICAgIHByaW50KHAgKyBnZ3RpdGxlKHgpKQoKfQpgYGAKCmBgYHtyfQojIGRlZmluZSBkYXRhc2V0cyB0byBwbG90IGludGVuc2l0aWVzLCBub3RjaCBwZXIgcHJvdGVpbiBhbmQgbWlzc2luZyB2YWx1ZXMgCgpkYXRhc2V0cyA8LSBsaXN0KGMoJzAsIDEwMCwgMCwgMCcpLCBjKCcwLjUsIDEwLCAwLCAwJykpIAoKcHNtX3Jlc19mbHQgJT4lIG5hbWVzKCkgJT4lIGxhcHBseShmdW5jdGlvbihhZ2MpewogIGRhdGFzZXRzICU+JSBsYXBwbHkoZnVuY3Rpb24odGhyZXNob2xkcyl7CiAgICBwcmludCh0aHJlc2hvbGRzKQogICAgYWxsIDwtIHBzbV9yZXNfZmx0W1thZ2NdXVtbdGhyZXNob2xkc11dCgogICAgaHMgPC0gYWxsW2ZEYXRhKGFsbCkkc3BlY2llcz09J0guc2FwaWVucyddCiAgICBzYyA8LSBhbGxbZkRhdGEoYWxsKSRzcGVjaWVzPT0nUy5jZXJldmlzaWFlJ10KICAgIAogICAgc2xpY2VzIDwtIGxpc3QoJ0FsbCc9YWxsLCAnSC5zYXBpZW5zJz1ocywgJ1MuY2VyZXZpc2lhZSc9c2MpCiAgICBmb3Ioc2xpY2UgaW4gbmFtZXMoc2xpY2VzKSl7CiAgICAgIHAgPC0gc2xpY2VzW1tzbGljZV1dICU+JSBwbG90X1RNVF9ub3RjaCgpICsKICAgICAgICB4bGFiKCdSZXBvcnRlciBpb24gaW50ZW5zaXR5IChsb2cyKScpICsKICAgICAgICBnZ3RpdGxlKHNwcmludGYoJyVzXG4lc1xuJXMnLCBhZ2MsIHRocmVzaG9sZHMsIHNsaWNlKSkKICAgICAgcHJpbnQocCkKICAgICAgCiAgICAgIHAyIDwtIHNsaWNlc1tbc2xpY2VdXSAlPiUgcGxvdF9UTVRfbm90Y2goZmFjZXRfYnlfc2FtcGxlPVRSVUUpICsKICAgICAgICB4bGFiKCdSZXBvcnRlciBpb24gaW50ZW5zaXR5IChsb2cyKScpICsKICAgICAgICBnZ3RpdGxlKHNwcmludGYoJyVzXG4lc1xuJXMnLCBhZ2MsIHRocmVzaG9sZHMsIHNsaWNlKSkKICAgICAgcHJpbnQocDIpCgogICAgfQogICAgCiAgICByZXR1cm4oTlVMTCkKICAgIAogICAgfSkKICAKICAKICByZXR1cm4oTlVMTCkKfSkKCmBgYAoKYGBge3J9CnRocmVzaG9sZHMgPC0gYygnMCwgMTAwLCAwLCAwJykgCgpwcmludCh0aHJlc2hvbGRzKQphbGwgPC0gcHNtX3Jlc19mbHRbWydBR0M6IDVFNCddXVtbdGhyZXNob2xkc11dCgpocyA8LSBhbGxbZkRhdGEoYWxsKSRzcGVjaWVzPT0nSC5zYXBpZW5zJ10Kc2MgPC0gYWxsW2ZEYXRhKGFsbCkkc3BlY2llcz09J1MuY2VyZXZpc2lhZSddCgpzbGljZXMgPC0gbGlzdCgnQWxsJz1hbGwsICdILnNhcGllbnMnPWhzLCAnUy5jZXJldmlzaWFlJz1zYykKZm9yKHNsaWNlIGluIG5hbWVzKHNsaWNlcykpewogIHAgPC0gc2xpY2VzW1tzbGljZV1dICU+JSBwbG90X1RNVF9ub3RjaCgpICsKICAgIHhsYWIoJ1JlcG9ydGVyIGlvbiBpbnRlbnNpdHkgKGxvZzIpJykgKwogICAgZ2d0aXRsZShzcHJpbnRmKCclc1xuJXMnLCB0aHJlc2hvbGRzLCBzbGljZSkpCiAgcHJpbnQocCkKICAKICBwMiA8LSBzbGljZXNbW3NsaWNlXV0gJT4lIHBsb3RfVE1UX25vdGNoKGZhY2V0X2J5X3NhbXBsZT1UUlVFKSArCiAgICB4bGFiKCdSZXBvcnRlciBpb24gaW50ZW5zaXR5IChsb2cyKScpICsKICAgIGdndGl0bGUoc3ByaW50ZignJXNcbiVzJywgdGhyZXNob2xkcywgc2xpY2UpKQogIHByaW50KHAyKQoKICBnZ3NhdmUoc3ByaW50ZignLi4vcmVzdWx0cy9wbG90cy8lc19pb25faW50ZW5zaXRpZXMucG5nJywgc2xpY2UpLCBwKQogIGdnc2F2ZShzcHJpbnRmKCcuLi9yZXN1bHRzL3Bsb3RzLyVzX2lvbl9pbnRlbnNpdGllc19wZXJfdGFnLnBuZycsIHNsaWNlKSwgcDIpCgp9CiAgICAKYGBgCgoKVGFsbGllcyBmb3IgZnJhY3Rpb24gc3ViLW5vdGNoIFBTTXMgcGVyIHByb3RlaW4KYGBge3J9CmRhdGFzZXRzIDwtIGxpc3QoYygnMC41LCAxMCwgMCwgMCcpKQoKcHNtX3Jlc19mbHQgJT4lIG5hbWVzKCkgJT4lIGxhcHBseShmdW5jdGlvbihhZ2MpewogIGRhdGFzZXRzICU+JSBsYXBwbHkoZnVuY3Rpb24odGhyZXNob2xkcyl7CgogICAgYWxsIDwtIHBzbV9yZXNfZmx0W1thZ2NdXVtbdGhyZXNob2xkc11dCiAgICBocyA8LSBhbGxbZkRhdGEoYWxsKSRzcGVjaWVzPT0nSC5zYXBpZW5zJ10KICAgIHNjIDwtIGFsbFtmRGF0YShhbGwpJHNwZWNpZXM9PSdTLmNlcmV2aXNpYWUnXQogICAgCiAgICBzbGljZXMgPC0gbGlzdCgnQWxsJz1hbGwsICdILnNhcGllbnMnPWhzLCAnUy5jZXJldmlzaWFlJz1zYykKICAgIGZvcihzbGljZSBpbiBuYW1lcyhzbGljZXMpKXsKICAgICAgCiAgICAgIG5vdGNoX3Blcl9wcm90ZWluIDwtIGdldF9ub3RjaF9wZXJfcHJvdGVpbihzbGljZXNbW3NsaWNlXV0pICU+JQogICAgICAgICBtdXRhdGUoc2FtcGxlPWZhY3RvcihyZW1vdmVfeChzYW1wbGUpLCBjb2xuYW1lcyhzbGljZXNbW3NsaWNlXV0pKSkKICAgICAgCiAgICAgIHByaW50KG5vdGNoX3Blcl9wcm90ZWluICU+JQogICAgICAgIGdyb3VwX2J5KHNhbXBsZSwgZnJhY3Rpb25fYmVsb3c+PTAuMjUpICU+JQogICAgICAgIHRhbGx5KCkpCiAgICAgIAogICAgICBwIDwtIG5vdGNoX3Blcl9wcm90ZWluICU+JQogICAgICAgIGZpbHRlcihmcmFjdGlvbl9iZWxvdz4wKSAlPiUgCiAgICAgICAgZ2dwbG90KGFlcyguZGF0YSRmcmFjdGlvbl9iZWxvdykpICsKICAgICAgICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTApICsgCiAgICAgICAgdGhlbWVfY2FtcHJvdChiYXNlX3NpemUgPSAxMCkgKwogICAgICAgIGZhY2V0X3dyYXAofnNhbXBsZSkgKyAKICAgICAgICB4bGFiKCJGcmFjdGlvbiBhdC9iZWxvdyBub3RjaCBQU01zIikgKwogICAgICAgIHlsYWIoIlByb3RlaW5zIikgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDAsMSwwLjUpKQogICAgICAgIAogICAgICAKICAgICAgcHJpbnQocCArIGdndGl0bGUoc3ByaW50ZignJXNcbiVzXG4lcycsIGFnYywgdGhyZXNob2xkcywgc2xpY2UpKSkKICAgICAgCiAgICAgIGlmKGFnYz09J0FHQzogNUU0JyAmIHNsaWNlPT0nQWxsJyl7CiAgICAgICAgZ2dzYXZlKCcuLi9yZXN1bHRzL3Bsb3RzL2ZyYWN0aW9uX3N1Yl9ub3RjaC5wbmcnLCBwKQogICAgICB9CiAgICB9CiAgICAKICAgIHJldHVybihOVUxMKQogIH0pCiAgCiAgcmV0dXJuKE5VTEwpCiAgCn0pCgoKYGBgCgoKTWlzc2luZyB2YWx1ZXMgZnJlcXVlbmNpZXMuCmBgYHtyfQpwc21fcmVzX2ZsdCAlPiUgbmFtZXMoKSAlPiUgbGFwcGx5KGZ1bmN0aW9uKGFnYyl7CiAgZGF0YXNldHMgJT4lIGxhcHBseShmdW5jdGlvbih0aHJlc2hvbGRzKXsKCiAgICBhbGwgPC0gcHNtX3Jlc19mbHRbW2FnY11dW1t0aHJlc2hvbGRzXV0KICAgIGhzIDwtIGFsbFtmRGF0YShhbGwpJHNwZWNpZXM9PSdILnNhcGllbnMnXQogICAgc2MgPC0gYWxsW2ZEYXRhKGFsbCkkc3BlY2llcz09J1MuY2VyZXZpc2lhZSddCiAgICAKICAgIHNsaWNlcyA8LSBsaXN0KCdBbGwnPWFsbCwgJ0guc2FwaWVucyc9aHMsICdTLmNlcmV2aXNpYWUnPXNjKQogICAgZm9yKHNsaWNlIGluIG5hbWVzKHNsaWNlcykpIHBsb3ROQShzbGljZXNbW3NsaWNlXV0sIHBOQSA9IDApCgogICAgcmV0dXJuKE5VTEwpCiAgfSkKICAKICByZXR1cm4oTlVMTCkKICAKfSkKCgoKYGBgCgpTYXZlIG91dCBvYmplY3RzIGZvciBkb3duc3RyZWFtIG5vdGVib29rcwpgYGB7cn0Kc2F2ZVJEUyhxdWFudF92c19tZWFuLCAnLi4vcmVzdWx0cy9xdWFudF92c19tZWFuLnJkcycpCnNhdmVSRFMocHNtX3Jlc19mbHQsICcuLi9yZXN1bHRzL3BzbV9yZXNfZmx0LnJkcycpCnNhdmVSRFMoZXhwZWN0ZWQsICcuLi9yZXN1bHRzL2V4cGVjdGVkLnJkcycpCmBgYAoKCg==